package com.um.jdy.app.charge.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.um.jdy.app.charge.entity.dto.EBoxStartParam;
import com.um.jdy.app.charge.entity.vo.EBOXOrderConfirmVO;
import com.um.jdy.app.charge.scheduled.EBoxOrderTask;
import com.um.jdy.app.core.manager.OrderRedisTemplate;
import com.um.jdy.common.activity.code.CouponsCode;
import com.um.jdy.common.activity.entity.vo.CouponsUserDetailVO;
import com.um.jdy.common.activity.entity.vo.DiscountsVO;
import com.um.jdy.common.activity.entity.vo.StationAvailableCouponsVO;
import com.um.jdy.common.activity.enums.ActivityEnum;
import com.um.jdy.common.activity.service.CouponsUserService;
import com.um.jdy.common.activity.service.DiscountsStationService;
import com.um.jdy.common.commons.manager.WxManager;
import com.um.jdy.app.device.manager.DeviceManager;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.charge.code.OrderCode;
import com.um.jdy.common.charge.entity.po.*;
import com.um.jdy.common.charge.entity.vo.EboxOrderVO;
import com.um.jdy.common.charge.entity.vo.OrderVO;
import com.um.jdy.common.charge.enums.OrderAction;
import com.um.jdy.common.charge.enums.OrderEnum;
import com.um.jdy.common.charge.enums.OrderException;
import com.um.jdy.common.charge.enums.OrderStopReason;
import com.um.jdy.common.charge.service.*;
import com.um.jdy.common.commons.properties.HshChargingProperties;
import com.um.jdy.common.commons.service.CommissionService;
import com.um.jdy.common.device.code.DeviceCode;
import com.um.jdy.common.device.entity.po.*;
import com.um.jdy.common.device.enums.DeviceEnum;
import com.um.jdy.common.device.service.*;
import com.um.jdy.common.finance.enums.FinancialEnum;
import com.um.jdy.common.finance.service.MerchantBillService;
import com.um.jdy.common.finance.service.PlatformBillService;
import com.um.jdy.common.finance.service.PlatformProfitBillService;
import com.um.jdy.common.finance.service.UserBillService;
import com.um.jdy.common.member.code.UserCode;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.entity.po.Wallet;
import com.um.jdy.common.member.enums.PayEnum;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.member.service.WalletService;
import com.um.jdy.common.platform.service.MerchantService;
import com.um.jdy.common.platform.service.SharingSettingService;
import com.um.jdy.common.push.service.PushService;
import com.um.jdy.common.sharing.service.ReceiverService;
import com.um.jdy.common.sharing.service.RecordsService;
import com.um.jdy.rpc.entity.EBoxPort;
import com.um.jdy.rpc.enums.DeviceTypeEnum;
import com.um.jdy.rpc.factory.ServiceFactory;
import com.um.jdy.rpc.notify.RpcEBoxOrderNotifyService;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.orm.entity.Response;
import com.um.springboot.starter.orm.manager.BaseManager;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.OrderUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.springboot.starter.utils.UMBeanUtils;
import com.um.springcloud.dubbo.cluster.DeviceKey;
import com.um.weixin.pay.service.WxBasePayService;
import com.um.weixin.pay.service.WxSharingService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * @Title
 * @Description
 * @Author renjunwei
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
@DubboService
public class EBoxOrderManager extends BaseManager<EboxOrderService> implements RpcEBoxOrderNotifyService {

    @Autowired
    PileService pileService;

    @Autowired
    GunService gunService;

    @Autowired
    MemberUserService userService;

    @Autowired
    OrderService orderService;

    @Autowired
    StationService stationService;

    @Autowired
    FeeEBoxPowerService feeEBoxPowerService;

    @Autowired
    FeeEBoxPriceService feeEBoxPriceService;

    @Autowired
    WalletService walletService;

    @Autowired
    MerchantService merchantService;

    @Autowired
    DeviceManager deviceManager;

    @Autowired
    HshProperties hshProperties;

    @Autowired
    EBoxOrderManager self;

    @Autowired
    HttpServletRequest request;

    @Autowired
    TaskScheduler taskScheduler;


    @Autowired
    EboxOrderService eboxOrderService;

    @Autowired
    EBoxOrderTask eBoxOrderTask;

    @Autowired
    UserBillService userBillService;

    @Autowired
    PlatformBillService platformBillService;

    @Autowired
    DataLogService dataLogService;

    @Autowired
    OrderPowerService orderPowerService;

    @Autowired
    MerchantBillService merchantBillService;

    @Autowired
    PlatformProfitBillService platformProfitBillService;

    @Autowired
    OrderCommissionService orderCommissionService;

    @Autowired
    PortAlarmRecordService alarmRecordService;

    @Autowired
    WxSharingService wxSharingService;

    @Autowired
    WxBasePayService wxPayService;

    @Autowired
    ReceiverService receiverService;

    @Autowired
    SharingSettingService sharingSettingService;

    @Autowired
    RecordsService recordsService;

    @Autowired
    OrderSkipPowerService orderSkipPowerService;

    @Autowired
    CommissionService commissionService;

    @Autowired
    OrderSharingService orderSharingService;

    @Autowired
    OrderEboxPowerService orderEboxPowerService;

    @Autowired
    OrderPlaceService orderPlaceService;

    @Autowired
    WxManager wxManager;

    @Autowired
    OrderRedisTemplate orderRedisTemplate;

    @Autowired
    ServiceFactory serviceFactory;

    @Autowired
    OrderManager orderManager;

    @Autowired
    HshChargingProperties hshChargingProperties;

    @Autowired
    PushService pushService;

    @Autowired
    CouponsUserService couponsUserService;

    @Autowired
    DiscountsStationService discountsStationService;
    
    /**
     * 开启充电
     *
     * @param param
     * @return
     */
    @Transactional
    public Map startCharge(EBoxStartParam param) {

        Pile pile = pileService.getEntity("code", param.getCode());
        if (pile == null) {
            throw new ServiceException(DeviceCode.NoDevice);
        }

        //查询充电网点信息
        Station station = stationService.getEntity(pile.getDeviceStationId());
        if (station == null) {
            throw new ServiceException(DeviceCode.NoStation);
        }

        if (!DeviceEnum.OpenStatus.Enable.name().equals(pile.getOpenState())) {
            throw new ServiceException(DeviceCode.DeviceNotEnabled);
        }

        if (!DeviceEnum.DeviceStatus.Online.name().equals(pile.getDeviceStatus())) {
            throw new ServiceException(DeviceCode.DeviceOffline);
        }

        Gun gun = gunService.getEntity(new String[]{"device_pile_id", "port"}, new Object[]{pile.getDevicePileId(), param.getGunNum()});
        if (gun == null) {
            throw new ServiceException(DeviceCode.NoGun);
        }

        if (!DeviceEnum.PortStatus.Available.name().equals(gun.getStatus())) {
            throw new ServiceException(DeviceCode.Unavailable);
        }

        MemberUser user = userService.get();
        String uid = user.getMemberUserId();


        //判断是否还有未完结订单，如果有，则抛出异常
//        List<OrderItemVO> orders = orderManager.getChargingOrders();
//        if(orders != null && orders.size() > 0) {
//            throw new ServiceException(OrderCode.HasUncompleteOrder, orders);
//        }

        //判断用户是否充电白名单 true-是 false-否
        boolean freeStatus = deviceManager.checkFreeUser(uid, pile.getDeviceStationId(), pile.getDevicePileId(),pile.getComId());

        // 检查充电口是否已被其他订单占用
        if (StrUtil.isNotBlank(gun.getOrderNo())) {
            Order otherOrder = orderService.getEntity("order_no", gun.getOrderNo());
            // 占用充电口的订单用户是当前用户，则取消旧订单
            if (otherOrder != null && uid.equals(otherOrder.getMemberUserId()) &&
                    PayEnum.Status.UnPayed.name().equals(otherOrder.getPayStatus())) {
                try {
                    self.cancelCharge(gun.getOrderNo());
                } catch (Exception ex) {
                    ex.printStackTrace();
                    log.error(ex.getMessage());
                }
            } else {
                throw new ServiceException(DeviceCode.PortOccupyByOrder);
            }
        }

        FeeEBoxPower feePower = feeEBoxPowerService.getViewModel("get_ebox_power_price_list", FeeEBoxPower.class, new String[]{pile.getDeviceFeeId()});
        if(feePower == null){
            throw new ServiceException(DeviceCode.NoFee);
        }

//        //价格(分)
        int payAmount = 0;
//        //功率(W)
        int power = feePower.getEndPower();

        //充电时长以秒计算，先充后付，充电时长设置为12小时
        int timeLength = 12 * 60 * 60;

        //非白名单用户检查余额是否大于等于10元 : TODO 修改为开柜拿电池再付款
        /*if (!freeStatus) {
            if (walletService.getBalance(uid,pile.getComId()) < 10 * 100) {
                throw new ServiceException(UserCode.NoBalance);
            }
        }*/

        String orderNo = OrderUtil.getOrderNo();
        String outTradeNo = OrderUtil.getWxOrderNo();

        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setOutTradeNo(outTradeNo);
        order.setDeviceStationId(pile.getDeviceStationId());
        order.setDevicePileId(pile.getDevicePileId());
        order.setDeviceName(pile.getName());
        order.setDeviceImei(pile.getImei());
        order.setDeviceCode(param.getCode());
        order.setDeviceGunId(gun.getDeviceGunId());
        order.setPort(gun.getPort());
        order.setMemberUserId(uid);
        order.setComId(pile.getComId());
        order.setPlatformMerchantId(station.getPlatformMerchantId());
        order.setCreateTime(DateUtil.date());
        order.setPaySeconds(timeLength);
        order.setPayAmount(freeStatus ? 0 : payAmount);//免费付款为0
        order.setPayStatus(PayEnum.Status.UnPayed.name());
        order.setPayWay(PayEnum.PayWay.Wallet.name());
        order.setStatus(OrderEnum.Status.NotStarted.name());
//        order.setItemPrice(getItemPriceText(feePrice));//TODO 1元3小时
        order.setIsFree(freeStatus ? YesOrNo.Yes.name() : YesOrNo.No.name());//免费订单
        order.setDeviceType(pile.getDeviceType());
        order.setDeviceFeeId(pile.getDeviceFeeId());
        order.setAutoUseCoupons(YesOrNo.Yes.name());
        if(freeStatus || null == param.getAutoUseCoupons() || !param.getAutoUseCoupons()){
            order.setAutoUseCoupons(YesOrNo.No.name());
            if(!freeStatus && StrUtil.isNotBlank(param.getActivityCouponsId())){
                CouponsUserDetailVO userCoupons = couponsUserService.getUserCoupons(param.getActivityCouponsId(), uid);
                if(null == userCoupons){
                    throw new ServiceException(CouponsCode.CouponsNotExist);
                }
                order.setActivityCouponsUserId(userCoupons.getActivityCouponsUserId());
                couponsUserService.saveCouponsUse(userCoupons.getActivityCouponsUserId());
            }
        }

        orderService.save(order);


        EboxOrder eboxOrder = new EboxOrder();
        eboxOrder.setChargePower(0);
        eboxOrder.setStartPower(feePower.getStartPower());
        eboxOrder.setEndPower(feePower.getEndPower());
        eboxOrder.setPowerPrice(feePower.getPrice());
        eboxOrder.setChargeOrderId(order.getChargeOrderId());
        eboxOrderService.save(eboxOrder);

        //用户如果还没有填写省市区，则自动保存
        if(StringUtil.isEmpty(user.getProvince())){
            userService.saveLocation(user,station.getProvince(),station.getCity(),station.getArea());
        }

        //记录分佣副本
        orderSharingService.addOrderSharing(order);
        //记录订单功率档位副本
        orderEboxPowerService.addOrderPower(pile.getDeviceFeeId(),order.getChargeOrderId());
        //记录订单占位费副本
        orderPlaceService.addPlaceAndTime(pile.getDeviceFeeId(),order.getChargeOrderId());

//        // 白名单不需要支付
//        if (!freeStatus) {
//            order.setPayWay(param.getPayWay().name());
//
//            if (PayEnum.PayWay.Wxpay == param.getPayWay()) { //微信支付
//                // 充电口占位
//                gun.setOrderNo(orderNo);
//                gunService.save(gun);
//
//                // 判断是否需要分账
//                if (isProfitSharing(getComId())) {
//                    order.setIsProfitSharing(YesOrNo.Yes.name());
//                    orderService.save(order);
//                }
//
//                //预下单，生成支付参数
//                String openId = user.getMiniOpenId();
//                String notifyUrl = StrUtil.builder(hshProperties.getConfig().getDomain(),
//                        "/api/v1/order/charge/ebox/wxpay/notify/", userService.getComId()).toString();
//
//                WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = null;
//                try {
//                    wxManager.getPayService(userService.getComId());
//                    jsapiResult = wxPayService.createOrderByJsapi(outTradeNo, openId,
//                            PayUtil.toTotalFee(payAmount), PayEnum.Title.Charge.getValue(), notifyUrl, isProfitSharing(getComId()));
//                } catch (WxPayException e) {
//                    throw new RuntimeException(e);
//                }
//
//                Map<String, Object> returnData = BeanUtil.beanToMap(jsapiResult, true, true);
//                returnData.put("charge_order_id", order.getChargeOrderId());
//                returnData.put("order_no", orderNo);
//
//                // 创建1分钟后未支付自动取消任务
//                taskScheduler.schedule(() -> eBoxOrderTask.timeoutUnpaidTask(orderNo),
//                        DateUtil.date().offset(DateField.SECOND, 30));
//
//                return returnData;
//            } else if (PayEnum.PayWay.Alipay == param.getPayWay()) { //支付宝支付
//                // 充电口占位
//                gun.setOrderNo(orderNo);
//                gunService.save(gun);
//
//                //支付宝支付
//                String notifyUrl = StrUtil.builder(hshProperties.getConfig().getDomain(), "/api/v1/order/charge/alipay/notify").toString();
//                AlipayTradeCreateResponse alipayTradeCreateResponse = null;
//                try {
//                    alipayTradeCreateResponse = Factory.Payment.Common()
//                            .asyncNotify(notifyUrl)
//                            .optional("timeout_express", "10m") //订单超时时间
//                            .create(PayEnum.Title.Charge.getValue(), outTradeNo, PayUtil.toDoubleAmountStr(payAmount), user.getAlipayUserId());
//                } catch (Exception e) {
//                    log.error("支付宝创建订单失败", e);
//                    throw new ServiceException("支付宝创建订单失败");
//                }
//
//                log.info("支付宝下单：" + cn.hutool.json.JSONUtil.toJsonStr(alipayTradeCreateResponse));
//
//                if (!ResponseChecker.success(alipayTradeCreateResponse)) {
//                    throw new ServiceException(CommonCode.Failed.getCode(), alipayTradeCreateResponse.getSubMsg());
//                }
//
//                Map payInfo = alipayTradeCreateResponse.toMap();
//                payInfo.put("order_no", orderNo);
//                payInfo.put("charge_order_id", order.getChargeOrderId());
//
//
//                // 创建1分钟后未支付自动取消任务
//                taskScheduler.schedule(() -> eBoxOrderTask.timeoutUnpaidTask(orderNo),
//                        DateUtil.date().offset(DateField.SECOND, 30));
//
//                return payInfo;
//
//            } else { //余额支付
//                Date payTime = DateUtil.date();
//
//                //记录钱包流水，金额为付款金额
//                Wallet memberWallet = new Wallet();
//                memberWallet.setMemberUserId(uid);
//                memberWallet.setOrderNo(orderNo);
//                memberWallet.setNo(OrderUtil.getOrderNo());
//                memberWallet.setType(FinancialEnum.IncomeOrExpend.Expend.name());
//                memberWallet.setAmount(payAmount);
//                memberWallet.setStatus(FinancialEnum.BillStatus.Effective.name());
//                memberWallet.setEvent(FinancialEnum.UserBillEvent.Charge.name());
//                memberWallet.setCreateTime(payTime);
//                walletService.save(memberWallet);
//
//                self.orderPaid(orderNo, payTime);
//
//                return MapUtil.builder().put("order_no", orderNo).put("charge_order_id", order.getChargeOrderId()).build();
//            }
//        } else {
//            Date payTime = DateUtil.date();
//            self.orderPaid(orderNo, payTime);
//            return MapUtil.builder().put("order_no", orderNo).put("charge_order_id", order.getChargeOrderId()).build();
//        }
        self.startDevice(orderNo);
        return MapUtil.builder().put("order_no", orderNo).put("charge_order_id", order.getChargeOrderId()).build();
    }


    @Lock4j(name = "processUnpaidOrder", keys = "#orderNo")
    @Transactional
    public void startDevice(String orderNo) {
        // 重新查一遍订单，避免落锁前订单已被改动
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            log.error("订单{}不存在！", orderNo);
            return;
        }

        if (PayEnum.Status.Payed.name().equals(order.getPayStatus())) {
            log.warn("订单{}已支付，忽略startDevice", orderNo);
            return;
        }

        String pileId = order.getDevicePileId();
        Pile pile = pileService.getRow(pileId);
        if (pile == null) {
            log.error("设备" + pileId + "不存在！");
            return;
        }
        //更新设备充电口状态
        Gun gun = gunService.getRow(order.getDeviceGunId());
        if (gun == null) {
            log.error("充电口" + order.getDeviceGunId() + "不存在！");
            return;
        }
        gun.setStatus(DeviceEnum.PortStatus.Preparing.name()); //启动中
        gun.setOrderNo(orderNo);
        gunService.updateRow(gun);

        String password = RandomUtil.randomString("123456789",4);
        while(eboxOrderService.getEntityBySqlName("get_ebox_order_by_password",new Object[]{order.getComId(),order.getDeviceCode(),password}) != null){
            password = RandomUtil.randomString("123456789",4);
        }

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id",order.getChargeOrderId());
        if(eboxOrder != null) {
            eboxOrder.setOpenPassword(password);
            eboxOrderService.updateRow(eboxOrder);
        }

        //添加到redis缓存
        orderRedisTemplate.setOrder(order.getDeviceCode(),order.getPort(),OrderEnum.Status.NotStarted,order.getChargeOrderId());

        String command = serviceFactory.getRpcEBoxDeviceService(pile.getProtocol()).reqStartCharge(order.getOrderNo(), new DeviceKey(pile.getImei()), gun.getPort(), order.getPaySeconds(),password);

        saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.StartChargeReq, DateUtil.date(), command, "开始充电，打打仓门密码："+password);

        // 创建15秒后未启动播放提示语音:充电柜不知道是否有这个功能
        //taskScheduler.schedule(() -> eBoxOrderTask.timeoutPlayTTSTask(orderNo),
        //        DateUtil.date().offset(DateField.SECOND, 15));

        // 创建30秒后未启动自动取消任务
        taskScheduler.schedule(() -> eBoxOrderTask.timeoutNotStartedTask(orderNo),
                DateUtil.date().offset(DateField.SECOND, 40));

    }

    public EBOXOrderConfirmVO confirm(String orderNo){
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            throw new ServiceException(OrderCode.NoOrder);
        }

        if(order.getPayStatus().equals(PayEnum.Status.Payed.name())) {
            throw new ServiceException(OrderCode.Paid);
        }


        if(!order.getStatus().equals(OrderEnum.Status.Completed.name())){
            throw new ServiceException(OrderCode.OrderUncomplete);
        }


        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        if(eboxOrder.getPlaceStatus().equals(OrderEnum.PlaceStatus.Place.name())) {
            throw new ServiceException(OrderCode.PlacingCannotPaid);
        }

        // int payAmount = order.getOrderAmount();
        int payAmount = order.getChargeAmount() + eboxOrder.getPlaceAmount();
        int finalPayAmount = payAmount;

        CouponsUserDetailVO selectedCoupons = null;

        // 自动使用优惠券
        if(YesOrNo.Yes.name().equals(order.getAutoUseCoupons())){
            List<StationAvailableCouponsVO> couponsList = couponsUserService.getStationAvailableList(order.getDeviceStationId(),
                    DeviceEnum.Type.EBox.name(), order.getMemberUserId());
            StationAvailableCouponsVO stationAvailableCouponsVO = couponsList.stream().filter(item -> item.getLimitMoney() <= finalPayAmount).findFirst().orElse(null);
            selectedCoupons = BeanUtil.toBean(stationAvailableCouponsVO, CouponsUserDetailVO.class);
            if(null != selectedCoupons){
                payAmount -= selectedCoupons.getMoney();
                couponsUserService.saveCouponsUse(selectedCoupons.getActivityCouponsUserId());
            }

            // 已选中优惠券
        }else if(StrUtil.isNotBlank(order.getActivityCouponsUserId())){
            selectedCoupons = couponsUserService.getUserCoupons(order.getActivityCouponsUserId());
            if(selectedCoupons.getLimitMoney() <= finalPayAmount){
                payAmount -= selectedCoupons.getMoney();
            }else{
                selectedCoupons = null;
            }
        }

        DiscountsVO selectedDiscount = null;
        if(null == selectedCoupons || YesOrNo.Yes.name().equals(selectedCoupons.getIsActivityMerge())){
            List<DiscountsVO> discountsList = discountsStationService.getDiscountsList(order.getDeviceStationId(),
                    DeviceEnum.Type.EBox.name());
            selectedDiscount = discountsList.stream().filter(item ->
                    item.getFullPrice() <= finalPayAmount).findFirst().orElse(null);
            if(null != selectedDiscount){
                payAmount -= ActivityEnum.DiscountsType.Money.name().equals(selectedDiscount.getType()) ?
                        selectedDiscount.getPrice() : payAmount * selectedDiscount.getScale() / 100;
            }
        }

        if(payAmount < 0){
            payAmount = 0;
        }

        EBOXOrderConfirmVO confirm = new EBOXOrderConfirmVO();
        confirm.setOrder(BeanUtil.toBean(order, OrderVO.class));
        confirm.setEboxOrder(BeanUtil.toBean(eboxOrder, EboxOrderVO.class));
        confirm.setSelectedCoupons(selectedCoupons);
        confirm.setDiscounts(selectedDiscount);
        confirm.setPayAmount(payAmount);
        return confirm;
    }


    @Lock4j(keys = "#orderNo")
    @Transactional
    public void orderPay(String orderNo) {

        EBOXOrderConfirmVO confirm = confirm(orderNo);

        int payAmount = confirm.getPayAmount();
        Order order = BeanUtil.toBean(confirm.getOrder(), Order.class);

        if(null != confirm.getSelectedCoupons()){
            order.setActivityCouponsUserId(confirm.getSelectedCoupons().getActivityCouponsUserId());
            order.setCouponsAmount(confirm.getSelectedCoupons().getMoney());
            order.setCouponsRemark(confirm.getSelectedCoupons().getTitle());
        }else if(StrUtil.isNotBlank(order.getActivityCouponsUserId())){
            couponsUserService.returnCouponsUse(order.getActivityCouponsUserId());
        }
        if(null != confirm.getDiscounts()){
            order.setDiscountsAmount(confirm.getDiscounts().getPrice());
            order.setDiscountsType(confirm.getDiscounts().getType());
            order.setDiscountsRemark(confirm.getDiscounts().getTitle());
        }

        String uid = order.getMemberUserId();

        Pile pile = pileService.getEntity("device_pile_id", order.getDevicePileId());
        if (pile == null) {
            throw new ServiceException(DeviceCode.NoDevice);
        }

        //判断用户是否充电白名单 true-是 false-否
        boolean freeStatus = deviceManager.checkFreeUser(uid, pile.getDeviceStationId(), pile.getDevicePileId(),pile.getComId());

        Date payTime = DateUtil.date();
        if(!freeStatus) {
            if(payAmount > 0) {

                if(walletService.getBalance(uid,order.getComId()) >= payAmount) {
                    //记录钱包流水，金额为付款金额
                    Wallet memberWallet = new Wallet();
                    memberWallet.setMemberUserId(uid);
                    memberWallet.setOrderNo(orderNo);
                    memberWallet.setNo(OrderUtil.getOrderNo());
                    memberWallet.setType(FinancialEnum.IncomeOrExpend.Expend.name());
                    memberWallet.setAmount(payAmount);
                    memberWallet.setStatus(FinancialEnum.BillStatus.Effective.name());
                    memberWallet.setEvent(FinancialEnum.WalletBillEvent.Charge.name());
                    memberWallet.setCreateTime(payTime);
                    walletService.save(memberWallet);

                    order.setPayStatus(PayEnum.Status.Payed.name());
                    order.setPayTime(payTime);
                    order.setPayAmount(payAmount);
                    order.setOrderAmount(payAmount);
                    order.setPayWay(PayEnum.PayWay.Wallet.name());
                    
                    //分佣计算-邓南辉新版计算方式
                    int profit = commissionService.calcCommission(order.getChargeOrderId(), order.getCreateTime(), orderNo, order.getOutTradeNo(), order.getPayAmount());
                    order.setProfit(profit);
                }else {
                    throw new ServiceException(UserCode.NoBalance);
                }
            }else{
                order.setPayStatus(PayEnum.Status.Payed.name());
                order.setPayTime(payTime);
            }
        }else{
            order.setPayStatus(PayEnum.Status.Payed.name());
            order.setPayTime(payTime);
        }
        orderService.updateRow(order);
    }

//    /**
//     * 订单支付后续处理
//     *
//     * @param orderNo
//     * @param payTime
//     * @throws Exception
//     */
//    @Lock4j(name = "processUnpaidOrder", keys = "#orderNo")
//    @Transactional
//    public void orderPaid(String orderNo, Date payTime) {
//        // 重新查一遍订单，避免落锁前订单已被改动
//        Order order = orderService.getRow("order_no", orderNo);
//        if (order == null) {
//            log.error("订单{}不存在！", orderNo);
//            return;
//        }
//
//        if (PayEnum.Status.Payed.name().equals(order.getPayStatus())) {
//            log.warn("订单{}已支付，忽略orderPaid", orderNo);
//            return;
//        }
//
//        Order updateOrder = new Order();
//        updateOrder.setChargeOrderId(order.getChargeOrderId());
//        updateOrder.setPayTime(payTime);
//        updateOrder.setPayStatus(PayEnum.Status.Payed.name()); //已支付
//        orderService.updateRow(updateOrder);
//
//        String pileId = order.getDevicePileId();
//        Pile pile = pileService.getRow(pileId);
//        if (pile == null) {
//            log.error("设备" + pileId + "不存在！");
//            return;
//        }
//
//        // 非白名单记录流水
//        if (!isFreeOrder(order)) {
//            // 微信或支付宝支付记录流水
//            if (!PayEnum.PayWay.Wallet.name().equals(order.getPayWay())) {
//                //插入用户账单流水：充电消费
//                UserBill userBill = new UserBill();
//                userBill.setComId(order.getComId());
//                userBill.setMemberUserId(order.getMemberUserId());
//                userBill.setNo(OrderUtil.getOrderNo());
//                userBill.setOutTradeNo(order.getOutTradeNo());
//                userBill.setOrderNo(orderNo);
//                userBill.setAmount(order.getPayAmount());
//                userBill.setType(FinancialEnum.IncomeOrExpend.Expend.name());//收入支出类型：0-收入，1-支出
//                userBill.setEvent(FinancialEnum.UserBillEvent.Charge.name());
//                userBill.setStatus(FinancialEnum.BillStatus.Effective.name());//账单状态：0未生效|1已生效|2已失效
//                userBill.setCreateTime(DateUtil.date());
//                userBillService.saveRow(userBill);
//
//                //插入平台账单流水：充电消费
//                PlatformBill platformBill = new PlatformBill();
//                platformBill.setComId(order.getComId());
//                platformBill.setNo(OrderUtil.getOrderNo());
//                platformBill.setOutTradeNo(order.getOutTradeNo());
//                platformBill.setOrderNo(orderNo);
//                platformBill.setAmount(order.getPayAmount());
//                platformBill.setType(FinancialEnum.IncomeOrExpend.Income.name());//收入支出类型：0-收入，1-支出
//                platformBill.setEvent(FinancialEnum.PlatformBillEvent.Charge.name());
//                platformBill.setStatus(FinancialEnum.BillStatus.Effective.name());//账单状态：0未生效|1已生效|2已失效
//                platformBill.setCreateTime(DateUtil.date());
//                platformBillService.saveRow(platformBill);
//            }
//        }
//
//
//        //订单超时未支付已被自动取消，执行退款操作
//        if (OrderEnum.Status.Completed.name().equals(order.getStatus())) {
//            log.error("订单{}超时未支付已被自动取消，执行退款操作", orderNo);
//            int remainSeconds = getOrderRemainSeconds(order, DateUtil.date());
//            self.chargeFinish(orderNo,OrderEnum.Status.Cancel, OrderStopReason.EBox.SYS_END.name(), remainSeconds, 0, true);
//
//            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
//                    "{}", "订单超时未支付已被自动取消");
//            return;
//        }
//
//        //更新设备充电口状态
//        Gun gun = gunService.getRow(order.getDeviceGunId());
//        if (gun == null) {
//            log.error("充电口" + order.getDeviceGunId() + "不存在！");
//            return;
//        }
//        gun.setStatus(String.valueOf(DeviceEnum.PortStatus.Preparing.name())); //启动中
//        gun.setOrderNo(orderNo);
//        gunService.updateRow(gun);
//
//        String command = serviceFactory.getRpcEBoxDeviceService(pile.getProtocol()).reqStartCharge(order.getOrderNo(), new DeviceKey(pile.getImei()), gun.getPort(), order.getPaySeconds());
//
//        saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.StartChargeReq, DateUtil.date(), command, "无");
//
//        // 创建15秒后未启动播放提示语音
////        taskScheduler.schedule(() -> eBoxOrderTask.timeoutPlayTTSTask(orderNo),
////                DateUtil.date().offset(DateField.SECOND, 15));
//
//        // 创建30秒后未启动自动取消任务
//        taskScheduler.schedule(() -> eBoxOrderTask.timeoutNotStartedTask(orderNo),
//                DateUtil.date().offset(DateField.SECOND, 30));
//    }

    /**
     * 统一处理订单结束方式 注意：本方法已按新设备及金额单位为分来处理，不需要再修改，除非有BUG
     *
     * @param orderNo       订单号
     * @param stopReason    设备结束类型
     * @param forceRefund   是否强行退款，无论订单是否结束都执行退款流程
     */
    @Lock4j(keys = "#orderNo")
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void chargeFinish(String orderNo,OrderEnum.Status status, String stopReason, boolean forceRefund) {
        //更新订单状态
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            return;
        }

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        Long beginEnergy = orderService.getBeginEnergy(order.getChargeOrderId());
        Long endEnergy = orderService.getEndEnergy(order.getChargeOrderId(),beginEnergy);
        int paySeconds = order.getPaySeconds();
        int chargeCapacity = orderService.getCapacity(order.getChargeOrderId());

        eboxOrder.setBeginEnergy(beginEnergy);
        eboxOrder.setEndEnergy(endEnergy);

        if (!forceRefund && OrderEnum.Status.Completed.name().equals(order.getStatus())) {
            if (chargeCapacity > eboxOrder.getChargeCapacity()) {
                log.info("订单{}已结束，只更新已充电度数", orderNo);
                eboxOrder.setChargeCapacity(chargeCapacity);

                order.setChargeCapacity(chargeCapacity);//多记录一个电量字段
                order.setEndTime(DateUtil.date());
                orderService.updateRow(order);
                eboxOrderService.updateRow(eboxOrder);
            } else {
                log.warn("订单{}已结束，忽略chargeFinish", orderNo);
            }
            return;
        }

        order.setStatus(status.name()); //充电完成
        order.setEndType(stopReason);

        //更新结束时间
        order.setEndTime(DateUtil.date());
        if (chargeCapacity > eboxOrder.getChargeCapacity()) {
            eboxOrder.setChargeCapacity(chargeCapacity);
            order.setChargeCapacity(chargeCapacity);//多记录一个电量字段
        }



        //String outTradeNo = order.getOutTradeNo();
        //避免充电停充没有上报秒数
        int chargeSeconds = getOrderChargeSeconds(order, DateUtil.date());
        int chargeCecilSeconds = 0; //按30分钟取整充电时长
        if (chargeSeconds >= 300) { //充电满5分钟才收费
            chargeCecilSeconds = getCeilTime(chargeSeconds); //按30分钟取整
            chargeCecilSeconds = Math.min(paySeconds, chargeCecilSeconds); //不能大于支付时长
        }

        int chargeAmount = (int) (eboxOrder.getPowerPrice() * NumberUtil.div(chargeCecilSeconds, 3600)); //实际充电金额
//        int returnAmount = 0; //退款金额

        //非免费充电
        if (!isFreeOrder(order)) {
            //充满自停：充电金额=当前的功率档位单价 * 时间
            order.setChargeAmount(chargeAmount);
            order.setOrderAmount(chargeAmount);
            eboxOrder.setChargeSeconds(chargeSeconds);
            eboxOrder.setEndEnergy(endEnergy);
        } else {
            //只记录充电金额
            order.setChargeAmount(0);//充电金额为0，才不影响其他报表统计
            order.setOrderAmount(0);
            order.setFreeAmount(chargeAmount);//增加免费金额字段来记录充电费用
            eboxOrder.setChargeSeconds(chargeSeconds);
            eboxOrder.setEndEnergy(endEnergy);
        }


        //不是异常订单才设置开始占位：设置占位费状态与开始时间
        if(YesOrNo.No.name().equals(order.getIsException())) {
            eboxOrder.setPlaceStatus(OrderEnum.PlaceStatus.Place.name());
            eboxOrder.setPlaceBeginTime(DateUtil.date());
        }


        order.setDuration(chargeSeconds);
        orderService.updateRow(order);
        eboxOrderService.updateRow(eboxOrder);

        //删除端口号的订单
        orderRedisTemplate.removeOrder(order.getDeviceCode(),order.getPort());
        orderRedisTemplate.removeChargeFull(order.getChargeOrderId());

        //推送
        pushService.pushChargeEnd(order);

    }

    /**
     * 用户取消充电
     *
     * @param orderNo
     * @return
     */
    public void cancelCharge(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.USER_CANCEL.name(), true);
    }

    /**
     * 用户停止充电
     *
     * @param orderNo
     * @return
     */
    public void stopCharge(String orderNo) throws Exception {
        // 重新查一遍订单，避免落锁前订单已被改动
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            throw new ServiceException(OrderCode.NoOrder);
        }

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id",order.getChargeOrderId());
        if(eboxOrder == null){
            throw new ServiceException(OrderCode.NoOrder);
        }

        if(StringUtil.equals(eboxOrder.getStartCloseDoor(),YesOrNo.No.name())){
            throw new ServiceException(OrderCode.NotStopForNeedCloseStartDoor);
        }

        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.USER_END.name(), false);
    }

    /**
     * 用户停止充电
     *
     * @param orderNo
     * @return
     */
    public void stopChargeByHeart(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.HEART.name(), true);
    }

    /**
     * 设备离线，用户结束充电
     *
     * @param orderNo
     * @return
     */
    public void stopOfflineCharge(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.OFFLINE_USER_END.name(), true);
    }

    /**
     * 设备离线，订单超时系统结束充电
     *
     * @param orderNo
     * @return
     */
    public void stopChargeTimeoutCharge(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.OFFLINE_SYS_END.name(), true);
    }


    public void fullStopCharge(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.FULLEND.name(), false);
    }

    public void timeEndStopCharge(String orderNo) throws Exception {
        self.cancelPaidOrder(orderNo, OrderStopReason.EBox.TIMEEND.name(), false);
    }

    /**
     * 判断插口是否空闲
     * @param orderId
     * @return
     */
    public  boolean isPortFree(String orderId){
        List<OrderPower> list = orderPowerService.getViewModelList("get_last_order_power_list",OrderPower.class,new Object[]{orderId,5});
        if(list.size() < 5){
            return false;
        }

        boolean portIsFree = true;
        for(OrderPower item : list){
            if(!StringUtil.equals(item.getStatus(), DeviceEnum.PortStatus.Available.name())){
                portIsFree = false;
                break;
            }
        }

        return portIsFree;
    }

    /**
     * 判断是否充满
     * @param orderId
     * @return
     */
    public boolean isChargeFull(String orderId){
        List<OrderPower> list = orderPowerService.getViewModelList("get_last_order_power_list",OrderPower.class,new Object[]{orderId,hshChargingProperties.getChargeFullDuration()});
        if(list.size() < hshChargingProperties.getChargeFullDuration()){
            return false;
        }

        boolean chargeFull = true;
        for(OrderPower item : list){
            if(item.getPower() > hshChargingProperties.getChargeFullPower()){
                chargeFull = false;
                break;
            }
        }

        return chargeFull;
    }

    /**
     * 判断是否计时结束:当设备不上报计时结束超过2分钟，平台自己结束
     * @param order
     * @return
     */
    public boolean isTimeEnd(Order order){
        int paySeconds = order.getPaySeconds();
        Date startTime = order.getCreateTime();
        int chargeSeconds = (int)Math.max(0,(new Date().getTime() - startTime.getTime())/1000);
        if(chargeSeconds - paySeconds >= 120){
            return true;
        }else{
            return false;
        }
    }

//    /**
//     * 查询最后的电量
//     * @param orderId
//     * @return
//     */
//    private Long getEndEnergy(String orderId,Long beginEnergy){
//        OrderPower item = orderPowerService.getEntityBySqlName("get_order_end_energy",new Object[]{orderId});
//        if(item == null){
//            return beginEnergy;
//        }else{
//            try {
//                return Math.max(beginEnergy, item.getEnergy());
//            }catch (Exception ex){
//                log.error("查询最后电量出错：{}",ex.getMessage());
//                return beginEnergy;
//            }
//        }
//    }

    /**
     * 取消已支付未完成订单
     *
     * @param orderNo
     * @param stopReason
     * @param forceStop  是否强行结束或取消订单，不调用设备
     * @throws Exception
     */
    @Lock4j(name = "processPaidOrder", keys = "#orderNo")
    @Transactional
    public void cancelPaidOrder(String orderNo, String stopReason, boolean forceStop) throws Exception {
        // 重新查一遍订单，避免落锁前订单已被改动
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            throw new ServiceException(OrderCode.NoOrder);
        }

        if (OrderEnum.Status.Completed.name().equals(order.getStatus())) {
            throw new ServiceException(OrderCode.OrderCompleted);
        }

        // 订单记录sysEndType
        order.setEndType(stopReason);
        orderService.updateRow(order);

        //EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id",order.getChargeOrderId());

        Pile pile = pileService.getRow(order.getDevicePileId());
        if (null == pile) { // 设备已被删除，强行结束订单
            log.warn("订单{}充电设备已被删除", order);
            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
                    "{}", "订单充电设备已被删除");
            self.chargeFinish(orderNo,OrderEnum.Status.Completed, OrderStopReason.EBox.SYS_END.name(), false);

            return;
        }

        String deviceName = pile.getImei();
        // 设备离线
        if (!DeviceEnum.DeviceStatus.Online.name().equals(pile.getDeviceStatus())) {
            if (forceStop) {

                String tempEndType = OrderStopReason.EBox.SYS_END.name();
                if (stopReason.equals(OrderStopReason.EBox.OFFLINE_SYS_END.name())) {
                    tempEndType = OrderStopReason.EBox.OFFLINE_SYS_END.name();
                }

                setExceptionOrder(order.getChargeOrderId(), OrderException.EBox.OfflineStoped);
                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
                        "{}", "订单充电设备不在线,订单超时或强制结束，开始占位");
                self.chargeFinish(orderNo, OrderEnum.Status.Completed, tempEndType, false);

            } else {
                log.warn("设备{}不在线，忽略取消订单{}", deviceName, orderNo);
            }
            return;
        }

        //启动未成功
        if (OrderEnum.Status.NotStarted.name().equals(order.getStatus())) {
            log.warn("订单{}启动未成功，取消订单,结束类型：{}", orderNo, stopReason);

            setExceptionOrder(order.getChargeOrderId(), OrderException.EBox.StartFailed);
            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
                    "{}", "订单启动未成功，取消订单");
            self.chargeFinish(orderNo, OrderEnum.Status.Failure, stopReason, false);


            return;
        }

        log.debug("stopCharge 订单停充开始");
        //设备停充 //|| StringUtil.toInt(order.getRemoteStopCount()) > 0
        if (forceStop) {
            log.warn("远程停止不成功，平台自己停止：{}", orderNo, stopReason);

            setExceptionOrder(order.getChargeOrderId(), OrderException.EBox.StopFailed);



            if(StringUtil.toInt(order.getRemoteStopCount()) > 0) {
                Map data = new Hashtable();
                data.put("remote_stop_count",StringUtil.toInt(order.getRemoteStopCount()));
                saveChargeData(order.getComId(),order.getChargeOrderId(),OrderAction.EBox.OrderFinish,new Date(),
                        JSONUtil.toJSONString(data),"远程设备停止不成功，平台自己停止及结算订单,开始占位");
            }else{
                saveChargeData(order.getComId(),order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
                        "{}", "平台自己停止及结算订单，停止类型："+OrderStopReason.EBox.valueOf(stopReason));
            }

            self.chargeFinish(orderNo,OrderEnum.Status.Completed,  stopReason, false);
        } else {

            // 订单记录remote_stop_count为1，如果下次还要停止（设备不回复或停止不了），平台直接结束
            order.setRemoteStopCount(StringUtil.toInt(order.getRemoteStopCount()) + 1);
            orderService.updateRow(order);

            String command = serviceFactory.getRpcEBoxDeviceService(pile.getProtocol()).reqStopCharge(order.getOrderNo(), new DeviceKey(pile.getImei()), order.getPort());

            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.StopChargeReq, new Date(), command, "无");
            log.debug("stopCharge 订单停充结束");
        }

    }

    /**
     * 取消未支付订单
     */
    @Lock4j(name = "processUnpaidOrder", keys = "#orderNo")
    @Transactional
    public void cancelUnpaidOrder(String orderNo) {
        // 重新查一遍订单，避免落锁前订单已被改动
        Order order = orderService.getRow("order_no", orderNo);
        if (order == null) {
            throw new ServiceException(OrderCode.NoOrder);
        }

        if (OrderEnum.Status.Completed.name().equals(order.getStatus())) {
            throw new ServiceException(OrderCode.OrderCompleted);
        }

        if (PayEnum.Status.Payed.name().equals(order.getPayStatus())) {
            throw new ServiceException(OrderCode.Paid);
        }

        Gun updateGun = new Gun();
        updateGun.setDeviceGunId(order.getDeviceGunId());
        updateGun.setOrderNo(StrUtil.EMPTY);
        gunService.updateRow(updateGun);

        Order updateOrder = new Order();
        updateOrder.setChargeOrderId(order.getChargeOrderId());
        order.setStatus(OrderEnum.Status.Completed.name());
        order.setEndType(OrderStopReason.EBox.PLATFORM_CANCEL.name());
        orderService.updateRow(updateOrder);


    }

    /**
     * 查询订单最后心跳时间
     *
     * @param orderId
     * @return
     */
    private Date getEndTime(String orderId) {
        List<OrderPower> list = orderPowerService.getList("charge_order_id", orderId, "create_time", "desc");
        if (list.size() > 0) {
            OrderPower item = list.get(0);
            return item.getCreateTime();
        }
        return null;
    }


    /**
     * 检查订单是否存在并且属于当前用户
     *
     * @param orderNo
     */
    public void checkUserOrderExits(String orderNo) {
        String userId = userService.get().getMemberUserId();
        Order order = orderService.getEntity(new String[]{"order_no", "member_user_id"}, new Object[]{orderNo, userId});
        if (null == order) {
            throw new ServiceException(OrderCode.NoOrder);
        }
    }

//    /**
//     * 微信支付回调
//     *
//     * @param request
//     */
//    public void wxPayNotify(HttpServletRequest request, String comId) {
//        WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = null;
//        try {
//            wxManager.getPayService(comId);
//            wxPayOrderNotifyV3Result = wxPayService.parseOrderNotify(request);
//        } catch (WxPayException e) {
//            log.error("解析微信支付通知失败", e);
//        }
//
//        Order order = orderService.getRow("out_trade_no", wxPayOrderNotifyV3Result.getResult().getOutTradeNo());
//        if (null == order) {
//            log.error("微信订单" + wxPayOrderNotifyV3Result.getResult().getOutTradeNo() + "不存在！");
//            return;
//        }
//        order.setTransactionId(wxPayOrderNotifyV3Result.getResult().getTransactionId());
//        orderService.updateRow(order);
//
//        self.orderPaid(order.getOrderNo(),
//                DateUtil.parse(wxPayOrderNotifyV3Result.getResult().getSuccessTime()));
//    }
//
//    /**
//     * 支付宝支付回调
//     *
//     * @param request
//     * @throws Exception
//     */
//    public void aliPayNotify(HttpServletRequest request) {
//
//        Map<String, String> parameters = ServletUtil.getParamMap(request);
//        log.info("支付宝充电支付回调异步通知：{}", cn.hutool.json.JSONUtil.toJsonStr(parameters));
//
//        boolean verifyResult = false;
//        try {
//            verifyResult = Factory.Payment.Common().verifyNotify(parameters);
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }
//
//        if (!verifyResult || !StrUtil.equals("TRADE_SUCCESS", parameters.get("trade_status"))) {
//            log.error("支付宝支付异步通知验签未通过！");
//        }
//
//        //处理订单支付后续
//        String outTradeNo = parameters.get("out_trade_no");
//        String payTime = parameters.get("gmt_payment");
//
//        Order order = orderService.getRow("out_trade_no", outTradeNo);
//        if (null == order) {
//            log.error("支付宝订单{}不存在！", outTradeNo);
//            return;
//        }
//
//        self.orderPaid(order.getOrderNo(), DateUtil.parse(payTime));
//    }

    private String getItemPriceText(FeeEBoxPrice feePrice) {
        //价格(分)
        int payAmount = feePrice.getPrice();
        return (payAmount / 100.0) + "元";
    }

    /**
     * 是否分账
     *
     * @return
     */
//    private boolean isProfitSharing(String comId) {
//        SharingSetting sharingSetting = sharingSettingService.getRow("com_id", comId);
//        if (null == sharingSetting) {
//            return false;
//        }
//        return StringUtil.equals(sharingSetting.getProfitSharing(), YesOrNo.Yes.name());
//    }

    /**
     * 获取订单剩余时间（秒）
     *
     * @param order
     * @param currentTime
     * @return
     */
//    private int getOrderRemainSeconds(Order order, Date currentTime) {
//        int remainSeconds = order.getPaySeconds();
//        // 订单已开始充电，以当前时间计算剩余时间
//        if (OrderEnum.Status.Charging.name().equals(order.getStatus())) {
//            Date startTime = order.getStartTime();
//            ///int chargeSeconds = (int) DateUtil.between(startTime, currentTime, DateUnit.SECOND, false);
//            remainSeconds = remainSeconds - (int) Math.max(0, (currentTime.getTime() - startTime.getTime()) / 1000);
//        }
//        return Math.max(0, remainSeconds);
//    }

    /**
     * 获取订单充电时间（秒）
     *
     * @param order
     * @param currentTime
     * @return
     */
    public int getOrderChargeSeconds(Order order, Date currentTime) {
        int paySeconds = order.getPaySeconds();
        Date startTime = order.getCreateTime();
        int chargeSeconds = (int) Math.max(0, (currentTime.getTime() - startTime.getTime()) / 1000);
        return Math.min(paySeconds, chargeSeconds);

    }





    /**
     * 不满60分钟，按60分钟收费
     *
     * @param time
     * @return
     */
    private int getHourCeilTime(int time) {
        int diff = time % 3600;
        return diff >= 60 ? time + (3600 - diff) : time - diff;
    }

    /**
     * 不满30分钟，按30分钟收费,当秒数超过60，才才会加30分钟
     *
     * @param time
     * @return
     */
    private int getCeilTime(int time) {
        int diff = time % 1800;
        return diff >= 60 ? time + (1800 - diff) : time - diff;
    }

    /**
     * 是否是免费充电订单
     *
     * @param order
     * @return
     */
    private boolean isFreeOrder(Order order) {
        return YesOrNo.Yes.name().equals(order.getIsFree());
    }

    /**
     * 保存记录订单操作日志
     *
     * @param orderId 订单ID
     * @param action  操作类型
     * @param time    时间
     * @param data    其他数据
     * @param remark  描述
     */
    private void saveChargeData(String comId, String orderId, OrderAction.EBox action, Date time, Object data, String remark) {
        DataLog dataLog = new DataLog();
        dataLog.setComId(comId);
        dataLog.setChargeOrderId(orderId);
        dataLog.setAction(action.name());
        dataLog.setActionZh(action.getValue());
        dataLog.setCreateTime(time);
        dataLog.setJsonData(cn.hutool.json.JSONUtil.toJsonStr(data));
        dataLog.setRemark(remark);
        dataLogService.saveRow(dataLog);
    }

    /**
     * 微信分账
     *
     * @param order
     */
//    public void wxProfitSharing(Order order) {
//        List<Receiver> list = receiverService.getRows("com_id", order.getComId());
//        if (null == list || list.size() == 0) {
//            log.error("分账失败，未设置分账收款用户！");
//            return;
//        }
//
//        SharingSetting sharingSetting = sharingSettingService.getRow("com_id", order.getComId());
//        if (null == sharingSetting) {
//            log.error("分账失败，未设置分账金额比例！");
//            return;
//        }
//
//        int rate = StringUtil.toInt(sharingSetting.getSharingRate());
//        long amount = (order.getPayAmount() - order.getReturnAmount()) * rate / 100;
//        if (amount <= 0) {
//            log.error("分账金额小于0，跳过分账！");
//            return;
//        }
//
//        Receiver receiverMap = list.get(RandomUtil.randomInt(0, list.size()));
//        String account = StringUtil.getTrim(receiverMap.getAccount());
//        ProfitSharingReceiver receiver = new ProfitSharingReceiver(StringUtil.getTrim(receiverMap.getType()),
//                account, amount, "分账");
//
//        String outTradeNo = OrderUtil.getWxOrderNo();
//        order.setProfitSharingOutTradeNo(outTradeNo);
//
//        ProfitSharingRequest req = new ProfitSharingRequest();
//        req.setAppid(wxManager.getPayService(order.getComId()).getConfig().getAppId());
//        req.setTransactionId(StringUtil.getTrim(order.getTransactionId()));
//        req.setOutOrderNo(outTradeNo);
//        req.setUnfreezeUnsplit(true);
//        req.setReceivers(ListUtil.toList(receiver));
//        ProfitSharingResult result = null;
//        try {
//            result = wxSharingService.profitSharing(req);
//        } catch (Exception e) {
//            log.error("分账错误！", e);
//            order.setProfitSharingStatus(OrderEnum.ProfitSharingStatus.FAIL.name());
//            orderService.updateRow(order);
//            return;
//        }
//        log.info("分账结果：{}", cn.hutool.json.JSONUtil.toJsonStr(result));
//        // TODO 检查一下同步返回的结果是否分账已完成，如果是处理中做个定时任务查询分账结果
//
//        order.setProfitSharingStatus(result.getState());
//        orderService.updateRow(order);
//
//        ProfitSharingResult.Receiver receiverResult = result.getReceivers().stream()
//                .filter(item -> item.getAccount().equals(account)).findFirst().get();
//
//        Records sharingRecords = new Records();
//        sharingRecords.setComId(order.getComId());
//        sharingRecords.setMemberUserId(receiverMap.getMemberUserId());
//        sharingRecords.setChargeOrderId(order.getChargeOrderId());
//        sharingRecords.setAccount(account);
//        sharingRecords.setOutTradeNo(outTradeNo);
//        sharingRecords.setSharingAmount((int) amount);
//        sharingRecords.setSharingRate(rate);
//        sharingRecords.setSharingDate(DateUtil.date());
//        sharingRecords.setSharingStatus(receiverResult.getResult());
//        sharingRecords.setSharingFailReason(receiverResult.getFailReason());
//        recordsService.saveRow(sharingRecords);
//
//    }

    /**
     * 记录跳档
     *
     * @param orderId    订单ID
     * @param power      原功率表
     * @param skipPower  跳档功率
     * @param startPower 档位开始功率
     * @param endPower   档位截止功率
     * @param price      单价：(分/小时）
     */
    private void recordSkipPower(String comId, String orderId, int power, int skipPower, int startPower, int endPower, int price, EBoxPort port) {
        saveChargeData(comId, orderId, OrderAction.EBox.SlipPower, new Date(),
                JSONUtil.toJSONString(port),
                "功率从" + power + "瓦跳到" + skipPower + "瓦，当前：" + startPower + "~" + endPower + "，单价：" + (price / 100.0) + "(元/小时)");
    }

    /**
     * 功率变大，调整订单时间
     *
     * @param order 订单
     * @param power 最大功率
     */
    public void adjustOrderTime(Order order, Integer power, Integer outTime, EBoxPort port) throws Exception {

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());


        if (eboxOrder == null) {
            log.error("adjustOrderTime ebOrder 为空:{}", order.getOrderNo());
            return;
        }

        // 功率超出当前收费最大功率，重新计算充电单价和充电时长

        OrderEboxPower orderEboxPower = orderEboxPowerService.getViewModel("get_ebox_fee_power_by_power", OrderEboxPower.class, new Object[]{order.getChargeOrderId(),order.getComId(), power, power});

        int oldPower = eboxOrder.getChargePower();

        Pile pile = pileService.getRow(order.getDevicePileId());
        if (pile == null) { // 设备已被删除
            log.warn("订单{}充电设备已被删除", order);
            return;
        }


        //超出价格表范围
        if (orderEboxPower == null && eboxOrder != null) {
            eboxOrder.setChargePower(port.getPower().intValue());
            order.setEndType(OrderStopReason.EBox.POWER_OVERLOAD.name());

            eboxOrderService.updateRow(eboxOrder);
            orderService.updateRow(order);

            //停充
            String command = serviceFactory.getRpcEBoxDeviceService(pile.getProtocol()).reqStopCharge("", new DeviceKey(pile.getImei()), port.getPort());

            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.StopChargeReq, new Date(),
                    command, "订单已超出最大允许功率，费率表中未查到适合的费率信息");
            return;
        }

        // 重新计算充电时长
        int newStartPower = orderEboxPower.getStartPower();
        int newEndPower = orderEboxPower.getEndPower();
        int newPrice = orderEboxPower.getPrice();

        if (newPrice <= 0) {
            log.warn("订单{}功率设置为0，不能调整价格", order);
            return;
        }

        //记录新的计费单价即可
        eboxOrder.setPowerPrice(newPrice);
        eboxOrder.setChargePower(power);
        eboxOrder.setStartPower(newStartPower);
        eboxOrder.setEndPower(newEndPower);
        eboxOrderService.updateRow(eboxOrder);

        recordSkipPower(order.getComId(), order.getChargeOrderId(), oldPower, power, newStartPower, newEndPower, newPrice, port);
    }

    /**
     * 更新充电最大功率
     *
     * @param order 订单
     * @param power 实时功率
     */
    public void adjustOrderMaxPower(Order order, int power) {
        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        if (eboxOrder != null) {
            int chargePower = eboxOrder.getChargePower();
            if (power > chargePower) {
                eboxOrder.setChargePower(power);
                eboxOrderService.updateRow(eboxOrder);
            }
        }

    }

    /**
     * 更新实时充电秒数
     *
     * @param order         订单
     * @param chargeSeconds 充电时间
     */
    public void updateChargeSecondsAndPower(Order order, int chargeSeconds, int power) {

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        if (eboxOrder != null) {
            //实时计算金额
            int duration = getOrderChargeSeconds(order, DateUtil.date());
            int feeChargeDuration = 0;
            if (duration >= 300) { //充电满5分钟才收费
                feeChargeDuration = getCeilTime(duration); //按30分钟取整
                feeChargeDuration = Math.min(order.getPaySeconds(), feeChargeDuration); //不能大于支付时长
            }


            //double price = eboxOrder.getPowerPrice() / 3600.0;//每秒

            int chargeAmount = (int)(feeChargeDuration / 3600.0 * eboxOrder.getPowerPrice());
//            if (feeChargeDuration >= order.getPaySeconds()) {
//                chargeAmount = payAmount;
//            } else {
//                chargeAmount = (int) (feeChargeDuration * price);
//                chargeAmount = Math.min(chargeAmount, payAmount);//不能大于支付金额
//            }

            order.setDuration(duration);
            order.setChargeAmount(chargeAmount);
            order.setOrderAmount(chargeAmount);

            eboxOrder.setChargeSeconds(chargeSeconds);
            eboxOrder.setCurrentPower(power);


            orderService.updateRow(order);
            eboxOrderService.updateRow(eboxOrder);
        }
    }

    /**
     * 开启充电，设备没有回调，需要修复单的状态为充电中
     *
     * @param port
     */
    public void fixNotStartOrder(Order order, EBoxPort port) {
        order.setStatus(OrderEnum.Status.Charging.name());
        orderService.saveRow(order);

        //记录订单缓存
        orderRedisTemplate.removeOrder(order.getDeviceCode(),order.getPort());
        orderRedisTemplate.setOrder(order.getDeviceCode(),order.getPort(),OrderEnum.Status.Charging,order.getChargeOrderId());

        saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.FixOrderCharging, new Date(),
                JSONUtil.toJSONString(port), "开启充电设备没有回调通知，修复订单状态为：充电中");

    }

    /**
     * 记录为异常订单
     *
     * @param orderId
     * @param exception
     */
    public void setExceptionOrder(String orderId, OrderException.EBox exception) {
        Order order = new Order();
        order.setChargeOrderId(orderId);
        order.setExceptionStatus(YesOrNo.No.name());
        order.setIsException(YesOrNo.Yes.name());
        order.setExceptionType(exception.name());
        orderService.updateRow(order);
    }

    /**
     * 查询端口正在充电中订单
     * @param deviceCode
     * @param port
     * @return
     */
    public Order getChargingOrder(String deviceCode, Integer port){
        List<Order> list = orderService.getRows(new String[]{"device_code","port","status"},new Object[]{deviceCode,port,OrderEnum.Status.Charging.name()},
                "create_time","desc");
        if(list.size() > 0)
            return list.get(0);
        else
            return null;
    }

    public Response openDoor(String code,String orderNo){
        Order order = orderService.getEntity("order_no",orderNo);
        if (order == null) {
            return Response.failed("订单不存在！");
        }

        if(!StringUtil.isEmpty(code) && !code.equals(order.getDeviceCode())){
            return Response.failed("此设备不存在该订单！");
        }

        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        if(StringUtil.equals(eboxOrder.getPlaceStatus(),OrderEnum.PlaceStatus.Completed.name())){
            return Response.failed("订单已完成！");
        }

        //判断用户是否充电白名单 true-是 false-否
        boolean freeStatus = deviceManager.checkFreeUser(order.getMemberUserId(), order.getDeviceStationId(), order.getDevicePileId(),order.getComId());

        //TODO 判断余额是否足够支付
        OrderVO orderVO = UMBeanUtils.copyBean(order, OrderVO.class);
        orderService.calcEBoxOrderPlaceFee(orderVO, UMBeanUtils.copyBean(eboxOrder, EboxOrderVO.class));
        int payAmount = orderVO.getOrderAmount();

        if(!freeStatus && payAmount > 0 && walletService.getBalance(order.getMemberUserId(),order.getComId()) < payAmount) {
            return Response.failed(UserCode.NoBalanceForOpen);
        }

        Pile pile = pileService.getEntity(order.getDevicePileId());
        String command = serviceFactory.getRpcEBoxDeviceService(pile.getProtocol()).reqOpenDoor(order.getOrderNo(), new DeviceKey(pile.getImei()), order.getPort());

        saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OpenDoorReq, new Date(), command, "无");

        return Response.success();
    }




    /*************************************************************************以下是RPC 回调的业务方法****************************************/

    /**
     * 开启充电：柜门打开上报
     *
     * @param seq      序列号
     * @param imei     IMEI码
     * @param port     端口
     */
    @Override
    public void respOpenDoor(String command, String seq, String imei, String protocol, Integer port) {

        // 仓门打开：启动成功，订单更新状态
        Order order = orderService.getRow(new String[]{"device_imei", "port", "status"}, new Object[]{imei,port, OrderEnum.Status.NotStarted.name()});
        if (order != null) {

            //更新设备充电口状态
            Gun gun = gunService.getRow(order.getDeviceGunId());
            if (gun != null) {
                gun.setStatus(DeviceEnum.PortStatus.Charging.name()); //充电中
                gunService.updateRow(gun);
            }

            order.setStatus(OrderEnum.Status.Charging.name());
            order.setStartTime(new Date());
            orderService.updateRow(order);

//            EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
//            if (eboxOrder != null) {
//                if(eboxPort.getPower().intValue() > StringUtil.toInt(eboxOrder.getChargePower())) {
//                    eboxOrder.setChargePower(eboxPort.getPower().intValue());
//                }
//                if(eboxOrder.getBeginEnergy() == null) {
//                    eboxOrder.setBeginEnergy(eboxPort.getEnergy());
//                }
//                eboxOrderService.updateRow(eboxOrder);
//            }
            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OpenDoorResp, new Date(), command, "设备回复仓门打开，订单创建成功");
        }else{
            Pile pile = pileService.getRow("imei",imei);
            if(pile == null)
                return;
            order = orderService.getEntityBySqlName("get_ebox_charged_and_place_order",pile.getComId(),pile.getCode(),port);
            log.debug("结束充电开门：{},{},{}",order,pile.getCode(),port);
            if(order != null){
                EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
                if (eboxOrder != null) {
                    eboxOrder.setStopOpenDoor(YesOrNo.Yes.name());
                    eboxOrderService.updateRow(eboxOrder);
                }

                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OpenDoorResp, new Date(), command, "设备回复仓门打开，占位结束");
            }
        }
    }


    /**
     * 结束充电：柜门关闭上报
     *
     * @param seq  序列号
     * @param imei IMEI码
     * @param port 端口
     */
    @Override
    public void respCloseDoor(String command, String seq, String imei,String protocol, Integer port) {

        //开始充电订单处理逻辑
        Order startChargingOrder = orderService.getEntityBySqlName("get_last_charge_order",imei, port, DeviceTypeEnum.EBox.name());
        if(startChargingOrder != null){
            EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", startChargingOrder.getChargeOrderId());
            if(eboxOrder == null)
                return;

            if(!startChargingOrder.getStatus().equals(OrderEnum.Status.Completed.name())){//
                eboxOrder.setStartCloseDoor(YesOrNo.Yes.name());
                eboxOrder.setStartCloseDoorTime(new Date());
                eboxOrderService.updateRow(eboxOrder);
                saveChargeData(startChargingOrder.getComId(), startChargingOrder.getChargeOrderId(), OrderAction.EBox.StartCloseDoorReq, new Date(), command, "无");
            }
            return;
        }


        //结束充电订单处理逻辑
        log.error("reqCloseDoor:{},{}",imei,port);
        Order order = orderService.getEntityBySqlName("get_last_unpaid_order", imei, port, DeviceTypeEnum.EBox.name());
        log.error("reqCloseDoor:{}",order);
        if (order == null) {
            return;
        }




        Pile pile = pileService.getRow("imei", imei);
        if (pile == null) {
            log.warn("结束充电，关门回复，设备不存在，订单: {}", order.getOrderNo());
            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.EndCloseDoorReq, new Date(),
                    command, "设备不存在");
            return;
        }

        Gun gun = gunService.getRow(order.getDeviceGunId());
        if (gun != null) {
            // 订单号一致则将充电口状态改回空闲
            if (order.getOrderNo().equals(gun.getOrderNo())) {
                gun.setOrderNo("");
                gun.setStatus(DeviceEnum.PortStatus.Available.name());
                gunService.updateRow(gun);
            }
        } else {
            log.warn("订单{}充电充电口不存在，忽略更新充电口状态", order.getOrderNo());
        }

        String uid = order.getMemberUserId();

        //判断用户是否充电白名单 true-是 false-否
        boolean freeStatus = deviceManager.checkFreeUser(uid, pile.getDeviceStationId(), pile.getDevicePileId(),pile.getComId());


        EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
        OrderPlace orderPlace = orderPlaceService.getRow("charge_order_id",eboxOrder.getChargeOrderId());

        Date placeEndTime = DateUtil.date();
        if(orderPlace != null) {

            eboxOrder.setPlaceStatus(OrderEnum.PlaceStatus.Completed.name());
            eboxOrder.setPlaceEndTime(placeEndTime);
            eboxOrder.setPlaceSeconds(eboxOrderService.getPlaceSeconds(orderPlace,eboxOrder));
            eboxOrder.setPlaceAmount(eboxOrderService.getPlaceAmount(orderPlace,eboxOrder));
        }

        eboxOrder.setStopCloseDoor(YesOrNo.Yes.name());
        eboxOrder.setStopCloseDoorTime(new Date());
        eboxOrder.setPlaceEndTime(placeEndTime);
        eboxOrder.setPlaceAmount(eboxOrder.getPlaceAmount());
        eboxOrder.setPlaceStatus(OrderEnum.PlaceStatus.Completed.name());

        String outTradeNo = order.getOutTradeNo();
        String orderNo = order.getOrderNo();

        order.setOrderAmount(order.getChargeAmount() + eboxOrder.getPlaceAmount());

        Date payTime = DateUtil.date();
        if(!freeStatus) {
            int payAmount = order.getOrderAmount();
            if(payAmount > 0) {

                orderService.updateRow(order);
                eboxOrderService.updateRow(eboxOrder);

                EBOXOrderConfirmVO confirm = confirm(orderNo);

                if(null != confirm.getSelectedCoupons()){
                    order.setActivityCouponsUserId(confirm.getSelectedCoupons().getActivityCouponsUserId());
                    order.setCouponsAmount(confirm.getSelectedCoupons().getMoney());
                    order.setCouponsRemark(confirm.getSelectedCoupons().getTitle());
                }else if(StrUtil.isNotBlank(order.getActivityCouponsUserId())){
                    couponsUserService.returnCouponsUse(order.getActivityCouponsUserId());
                }
                if(null != confirm.getDiscounts()){
                    order.setDiscountsAmount(confirm.getDiscounts().getPrice());
                    order.setDiscountsType(confirm.getDiscounts().getType());
                    order.setDiscountsRemark(confirm.getDiscounts().getTitle());
                }

                payAmount = confirm.getPayAmount();

                if(walletService.getBalance(uid,order.getComId()) >= payAmount) {
                    //记录钱包流水，金额为付款金额
                    Wallet memberWallet = new Wallet();
                    memberWallet.setMemberUserId(uid);
                    memberWallet.setComId(order.getComId());
                    memberWallet.setOrderNo(orderNo);
                    memberWallet.setNo(OrderUtil.getOrderNo());
                    memberWallet.setType(FinancialEnum.IncomeOrExpend.Expend.name());
                    memberWallet.setAmount(payAmount);
                    memberWallet.setStatus(FinancialEnum.BillStatus.Effective.name());
                    memberWallet.setEvent(FinancialEnum.WalletBillEvent.Charge.name());
                    memberWallet.setCreateTime(payTime);
                    walletService.saveRow(memberWallet);

                    order.setPayStatus(PayEnum.Status.Payed.name());
                    order.setPayTime(payTime);
                    order.setPayAmount(payAmount);
                    order.setPayWay(PayEnum.PayWay.Wallet.name());

                    saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.EndCloseDoorReq, new Date(),
                            command, "拿走电池，仓门关闭，开始计算分佣");
                    log.warn("结束充电，关门回复，开始计算分佣，订单: {}", order.getOrderNo());
                    //分佣计算-邓南辉新版计算方式
                    int profit = commissionService.calcCommission(order.getChargeOrderId(), order.getCreateTime(), orderNo, outTradeNo, order.getPayAmount());
                    order.setProfit(profit);
                }else{
                    saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.EndCloseDoorReq, new Date(),
                            command, "拿走电池，仓门关闭：用户余额不足，等待支付");
                    log.warn("结束充电，关门回复，用户余额不足，等待支付，订单: {}", order.getOrderNo());
                }
            }else{

                // 付款金额为0, 退回优惠券
                if(StrUtil.isNotBlank(order.getActivityCouponsUserId())){
                    couponsUserService.returnCouponsUse(order.getActivityCouponsUserId());
                }

                order.setPayStatus(PayEnum.Status.Payed.name());
                order.setPayTime(payTime);
                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.EndCloseDoorReq, new Date(),
                        command, "拿走电池，仓门关闭：订单金额为0，不需要支付");
            }
        }else{
            order.setPayStatus(PayEnum.Status.Payed.name());
            order.setPayTime(payTime);
            saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.EndCloseDoorReq, new Date(),
                    command, "拿走电池，仓门关闭：免费订单，不需要支付");
        }



        //查询充电网点的价格
//        Station station = stationService.getRow(order.getDeviceStationId());
//        if (station == null) {
//            log.warn("订单{}网点不存在，忽略佣金分配操作", orderNo);
//            orderService.updateRow(order);
//            eboxOrderService.updateRow(eboxOrder);
//            return;
//        }

        orderService.updateRow(order);
        eboxOrderService.updateRow(eboxOrder);



        // 分账
//        log.info("订单[{}]开始分账", order.getOrderNo());
//        if (YesOrNo.Yes.name().equals(order.getIsProfitSharing())) {
//            if (PayEnum.PayWay.Wxpay.name().equals(order.getPayWay())) {
//                this.wxProfitSharing(order);
//            }
//        }
    }

    /**
     * 设备端口上报
     *
     * @param seq   序列号
     * @param imei  IMEI码
     * @param ports 端口列表
     */
    @Override
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void reqPortsNotify(String cmd, String seq, String imei,String protocol, List<EBoxPort> ports) {

        serviceFactory.getRpcEBoxDeviceService(protocol).respPortsNotify(seq, new DeviceKey(imei));

        Pile pile = pileService.getRow("imei", imei);
        if (pile == null)
            return;

        for (EBoxPort port : ports) {
            //记录订单实时数据
            Order order = getChargingOrder(pile.getCode(), port.getPort());
            log.info("socketNotify order:{}", order);
            if (order != null && !port.getState().equals(DeviceEnum.PortStatus.Charging.name())) {

                //再次检查订单状态，防止有并发进入，本方法未加锁
                order = orderService.getRow("order_no", order.getOrderNo());
                if (OrderEnum.Status.Completed.name().equals(order.getStatus())) {
                    log.warn("订单{}已结束，忽略socketNotify", order.getOrderNo());
                    continue;
                }

                OrderStopReason.EBox stopReason = OrderStopReason.EBox.valueOf(port.getStopReason());
                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.DeviceStopChargeReq, new Date(),
                        cmd, "设备通知停止充电，停止类型：" + (stopReason != null ? stopReason.getValue() : port.getState()));

                self.chargeFinish(order.getOrderNo(),OrderEnum.Status.Completed,  port.getStopReason(), false);

                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(),
                        cmd, "正常结束，开始占位");


            }

            //告警记录
//            if (pile != null && port.getState().equals(DeviceEnum.PortStatus.Faulted.name())) {
//
//                PortAlarmRecord record = new PortAlarmRecord();
//                record.setDevicePileId(pile.getDevicePileId());
//                record.setCode(pile.getCode());
//                record.setDeviceName(pile.getImei());
//                record.setGunNum(port.getPort());
//                //record.setAlarmCode(port.getState());
//                record.setCreateTime(new Date());
//                record.setComId(pile.getComId());
//                alarmRecordService.saveRow(record);
//
//                //TODO 推送
//
//            }
        }
    }

    /**
     * 回复开始充电
     *
     * @param seq        序列号
     * @param imei IMEI码
     * @param port       端口
     * @param ports      端口列表
     */
    @Override
    @Transactional
    public void respStartCharge(String cmd, String seq, String imei, Integer port, List<EBoxPort> ports) {
        // 启动成功，订单更新状态
        Order order = orderService.getRow(new String[]{"device_imei", "port", "status"}, new Object[]{imei,port, OrderEnum.Status.Charging.name()});
        if (order != null) {
            EBoxPort eboxPort = null;
            for (EBoxPort item : ports) {
                if (item.getPort() == port && item.getState().equals(DeviceEnum.PortStatus.Charging.name())) {
                    eboxPort = item;
                    break;
                }
            }

            if (eboxPort != null) {
                log.debug("startChargeResp 订单开始");

                //更新设备充电口状态
                Gun gun = gunService.getRow(order.getDeviceGunId());
                if (gun != null) {
                    gun.setStatus(DeviceEnum.PortStatus.Charging.name()); //充电中
                    gunService.updateRow(gun);
                }

                EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id", order.getChargeOrderId());
                if (eboxOrder != null) {
                    if(eboxPort.getPower().intValue() > StringUtil.toInt(eboxOrder.getChargePower())) {
                        eboxOrder.setChargePower(eboxPort.getPower().intValue());
                    }
                    if(eboxOrder.getBeginEnergy() == null) {
                        eboxOrder.setBeginEnergy(eboxPort.getEnergy());
                    }
                    eboxOrder.setChargeStatus(OrderEnum.ChargeStatus.Charge.name());
                    eboxOrderService.updateRow(eboxOrder);
                }

                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.PortChargeStatusUpdate, new Date(), "", "仓口充电状态变更为：充电中");

                //记录订单缓存
                orderRedisTemplate.removeOrder(order.getDeviceCode(),order.getPort());
                orderRedisTemplate.setOrder(order.getDeviceCode(),order.getPort(),OrderEnum.Status.Charging,order.getChargeOrderId());

                //saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.StartChargeResp, new Date(), cmd, "设备回复开始充电成功");
            }
        }
    }

    /**
     * 回复结束充电
     *
     * @param seq   序列号
     * @param imei  IMEI码
     * @param port  端口
     * @param ports 端口列表
     */
    @Override
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void respStopCharge(String cmd, String seq, String imei, Integer port, List<EBoxPort> ports) {
        Pile pile = pileService.getRow("imei", imei);
        if (pile == null)
            return;

        Order order = getChargingOrder(pile.getCode(), port);
        if (order != null) {

            EBoxPort eboxPort = null;
            for (EBoxPort item : ports) {
                if (item.getPort() == port) {
                    eboxPort = item;
                    break;
                }
            }

            if (eboxPort != null && !eboxPort.getState().equals(DeviceEnum.PortStatus.Charging.name())) {

                //再次检查订单状态，防止有并发进入，本方法未加锁
                order = orderService.getRow("order_no", order.getOrderNo());

                if (OrderEnum.Status.Completed.name().equals(order.getStatus())) {
                    log.warn("订单{}已结束，忽略stopCharge", seq);
                    return;
                }

                EboxOrder eboxOrder = eboxOrderService.getRow("charge_order_id",order.getChargeOrderId());
                if(eboxOrder != null) {
                    if (YesOrNo.No.name().equals(eboxOrder.getStartCloseDoor())) {
                        log.warn("订单{}柜门未关闭，忽略stopCharge", seq);
                        return;
                    }
                    log.debug("stopCharge 订单结算开始");
                    eboxOrder.setChargeStatus(OrderEnum.ChargeStatus.Completed.name());
                    eboxOrderService.updateRow(eboxOrder);
                    saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.PortChargeStatusUpdate, new Date(), cmd, "仓口充电状态变更为：结束充电");
                }
                //String orderNo = StringUtil.getTrim(order.get("order_no"));
                String endType = OrderStopReason.EBox.USER_END.name();
                if (OrderStopReason.EBox.ADMIN_END.name().equals(order.getEndType()))
                    endType = OrderStopReason.EBox.ADMIN_END.name();

                self.chargeFinish(order.getOrderNo(),OrderEnum.Status.Completed,  endType, false);

                saveChargeData(order.getComId(), order.getChargeOrderId(), OrderAction.EBox.OrderFinish, new Date(), cmd, "正常结束，开始占位");
            }
        }
    }
}
